package br.ufrj.ad.evento;

import java.util.List;

import org.apache.log4j.Logger;

import br.ufrj.ad.As;
import br.ufrj.ad.entidade.Peer;
import br.ufrj.ad.entidade.Publisher;
import br.ufrj.ad.entidade.Rodada;
import br.ufrj.ad.entidade.Seed;
import br.ufrj.ad.estatistica.Amostragem;

public abstract class Upload extends Evento {
	private static final Logger log = Logger.getLogger(Upload.class);
			
	public Upload(double tempo, Peer peer, Rodada rodada, As as) {
		super(tempo, peer, rodada, as);
	}

	@Override
	void proximoEvento(Rodada rodadaProximoEvento) {
		
		if(as.parametros.cenario != 70) {
		
		Peer peerDestino = peer.escolheDestinoUpload();
		if(peerDestino != null) {
			int blocoId = peer.escolheBloco(peerDestino);
			boolean virouSeed = peerDestino.recebeBloco(blocoId);
			
			// se blocoId < 0 não teve upload e o peer não virou seed
			if(virouSeed) {
				//já recebeu todos os blocos
				log.debug(peer+" upou para "+peerDestino);
				Seed seed = new Seed(peerDestino);
				//o tempo que durou o download é agora - quando o cara chegou pq ele terminou o download aqui e está virando seed.
				rodada.addTempoDownload(tempo, tempo - seed.getTempoChegada());
				seed.setTempoSaida(tempo + Amostragem.exponencial(as.parametros.GAMA));
				as.eventos.add(new Saida(seed, rodadaProximoEvento, as));
				
				as.peers.remove(peerDestino);
				as.eventos.removeAll(peerDestino.getUploadsAgendados());
				
				//peerDestino deixou de ser um peer e virou seed pq recebeu o arquivo já
				as.seeds.add(seed);
				
				double tempoUpload = tempo + Amostragem.exponencial(as.parametros.MI);
				if(tempoUpload < seed.getTempoSaida()) {
					as.eventos.add(new SeedUpload(tempoUpload , seed, rodadaProximoEvento, as));
				}
			}
		}
		
		} else {
			boolean comPublisher = false;
			
			boolean virouSeed = false;
			List<Peer> peers3 = peer.sample3Peers();
			if(!peer.temBloco()) {
				log.debug("não tem bloco download rare match "+peer);
				peer.downloadRareMatch(peers3);
				log.debug(peer);
			} else if(peer.temKmenos1Blocos()) {
				log.debug("k - 1 blocos download especial "+peer);
				virouSeed = peer.downloadFaltando1(peers3);
				
				if(virouSeed)
					log.debug("BAIXOU E SAIU " + peer);
				else
					log.debug("Não baixou.");
			} else if(peer instanceof Publisher && comPublisher) {
				Peer p = peer.escolheDestinoUpload();
				int b = peer.escolheBloco(p);
				boolean virouSeedPeloPublisher = p.recebeBloco(b); 
				log.debug(peer+" -> "+p);
				if(virouSeedPeloPublisher) {
					Seed s = new Seed(p);
					rodada.addTempoDownload(tempo, tempo - s.getTempoChegada());
					s.setTempoSaida(tempo);
					as.eventos.add(new Saida(s, rodadaProximoEvento, as));
					
					as.peers.remove(p);
					as.eventos.removeAll(p.getUploadsAgendados());
				}
			} else if (!(peer instanceof Publisher)){
				log.debug("download qualquer "+peer);
				peer.downloadQualquer();
				log.debug(peer);
			}
			
			if(virouSeed) {
				Seed s = new Seed(peer);
				rodada.addTempoDownload(tempo, tempo - s.getTempoChegada());
				s.setTempoSaida(tempo);
				as.eventos.add(new Saida(s, rodadaProximoEvento, as));
				
				as.peers.remove(peer);
				as.eventos.removeAll(peer.getUploadsAgendados());
				
			}
		}
		
		agendaProximoUpload(rodadaProximoEvento);
	}

	abstract void agendaProximoUpload(Rodada rodada);
}
